#pragma once

class CPlayer;
class CCamera;
class CGameObject;
class CScene;
class CTerrain;


typedef struct tagCALLBACKFUNCTION   
{
    LPVOID						m_pfCallback;          
    LPVOID						m_pContext;         
} CALLBACKFUNCTION;

typedef bool(*LPUPDATEPLAYERCALLBACK)(LPVOID pContext, CPlayer *pPlayer, float fTimeScale);
typedef bool(*LPUPDATECAMERACALLBACK)(LPVOID pContext, CCamera *pCamera, float fTimeScale);

class CPlayer
{
private:
    CCamera						*m_pCamera;              
    CGameObject					*m_p3rdPersonObject;     
    BOUNDINGCUBE				m_bcBoundingCube;               
    ULONG						m_nCameraMode;           

    D3DXVECTOR3					m_vPosition;          
    D3DXVECTOR3     			m_vUp;                
    D3DXVECTOR3     			m_vRight;             
    D3DXVECTOR3     			m_vLookAt;      

    D3DXVECTOR3     			m_vCameraOffset;  

	D3DXMATRIX					m_mMeshBaseTransform;
	bool						m_bBaseTransform;
	float						m_fFloat;

    float           			m_fPitch;             
    float           			m_fRoll;              
    float           			m_fYaw;               

    D3DXVECTOR3					m_vVelocity;          
    D3DXVECTOR3     			m_vGravity;           
    float           			m_fMaxVelocityXZ;     
    float           			m_fMaxVelocityY;      
    float           			m_fFriction;          
    float           			m_fCameraLag;         

    CALLBACKFUNCTION   			*m_pUpdatePlayer;   
    CALLBACKFUNCTION   			*m_pUpdateCamera;   
    unsigned short     			m_nUpdatePlayerCount;   
    unsigned short     			m_nUpdateCameraCount;   
public:
    CPlayer();
    ~CPlayer();

    void Set3rdPersonObject(CGameObject *pObject) { m_p3rdPersonObject = pObject; }
    void SetFriction(float fFriction) { m_fFriction = fFriction; }
    void SetGravity(const D3DXVECTOR3& vGravity) { m_vGravity = vGravity; }
    void SetMaxVelocityXZ(float fMaxVelocity) { m_fMaxVelocityXZ = fMaxVelocity; }
    void SetMaxVelocityY(float fMaxVelocity) { m_fMaxVelocityY = fMaxVelocity; }
    void SetVelocity(const D3DXVECTOR3& vVelocity) { m_vVelocity = vVelocity; }
    void SetCameraLag(float fCameraLag) { m_fCameraLag = fCameraLag; }
    void SetCameraOffset(const D3DXVECTOR3& vOffset);
    void SetBoundingCube(const BOUNDINGCUBE& bcBoundingCube) { m_bcBoundingCube = bcBoundingCube; }

    bool SetCameraMode(ULONG nMode);

	void SetFloat(const float& PlayerFloat);
	void SetBaseRotation(const D3DXMATRIX& RotationMatrix);
	void SetPitchForTerrain(CTerrain* Terrain);
	D3DXMATRIX GetTransform(void);

	float GetFloat(void);

    const BOUNDINGCUBE& GetBoundingCube() const { return(m_bcBoundingCube); }
    CCamera *GetCamera() const { return(m_pCamera); }
    const D3DXVECTOR3& GetVelocity() const { return(m_vVelocity); }
    const D3DXVECTOR3& GetCameraOffset() const { return(m_vCameraOffset); }
    const D3DXVECTOR3& GetPosition() const { return(m_vPosition); }
    const D3DXVECTOR3& GetLookAtVector() const { return(m_vLookAt); }
    const D3DXVECTOR3& GetUpVector() const { return(m_vUp); }
    const D3DXVECTOR3& GetRightVector() const { return(m_vRight); }
    
    float GetYaw() const { return(m_fYaw); }
    float GetPitch() const { return(m_fPitch); }
    float GetRoll() const { return(m_fRoll); }
    D3DXVECTOR3 GetPitchYawRoll() { return(D3DXVECTOR3(m_fPitch, m_fYaw, m_fRoll)); }

    void SetPosition(const D3DXVECTOR3& vPosition) { Move(vPosition-m_vPosition); }

    void UpdateVelocity(ULONG nDirection, float fDistance);
    bool Move(const D3DXVECTOR3& vShift);
	
	void SetRotationVector(D3DXVECTOR3 Look, D3DXVECTOR3 Right, D3DXVECTOR3 Up); 
    void Rotate(float x, float y, float z);
	void ResetRotation(void);

    void Update(float fTimeScale);
    
    void Render(LPDIRECT3DDEVICE9 pDevice, CCamera* Camera = NULL, CScene* Scene = NULL);	

	void AddPlayerCallback(LPUPDATEPLAYERCALLBACK pFunction, LPVOID pContext);
    void AddCameraCallback(LPUPDATECAMERACALLBACK pFunction, LPVOID pContext);
    void RemovePlayerCallback(LPUPDATEPLAYERCALLBACK pFunction, LPVOID pContext);
    void RemoveCameraCallback(LPUPDATECAMERACALLBACK pFunction, LPVOID pContext);
};


